/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bgu.dcr.tp.cfg;

import java.lang.reflect.Method;

/**
 *
 * @author Shl
 */
public class ConfigurableElement {

    private String name;
    private boolean mandatory;
    private String defaultValue;
    private Class type, keyType, valueType;
    private String description;
    private Method getter, setter;
    private SocketType sockType;

    public ConfigurableElement(Class c, Method m, MarkProperty annotation) {
        sockType = null;
        this.name = annotation.name();
        if (name.isEmpty()) {
            this.name = m.getName();
        }

        this.mandatory = annotation.mandatory();
        this.defaultValue = annotation.defaultValue();
        this.description = annotation.description();

        resolveGettersAndSetters(m, c);

        type = getter.getReturnType();
    }

    public ConfigurableElement(Class c, Method m, MarkSocket annotation) {
        sockType = annotation.type();
        this.name = annotation.name();
        if (name.isEmpty()) {
            this.name = m.getName();
        }

        this.mandatory = annotation.mandatory();
        this.description = annotation.description();

        resolveGettersAndSetters(m, c);

        type = getter.getReturnType();
        keyType = annotation.keyType();
        valueType = annotation.valueType();
    }

    private void resolveGettersAndSetters(Method m, Class c) throws ConfigurationException {
        this.getter = m;
        this.setter = null;
        if (!isGetter(getter) && isSetter(getter)) {
            setter = getter;
            try {
                getter = c.getMethod("get" + m.getName().substring("get".length()), setter.getParameterTypes()[0]);
            } catch (NoSuchMethodException | SecurityException ex) {
                throw new ConfigurationException("class " + c.getCanonicalName() + " has no corresponding getter for: " + m.getName());
            }
        } else if (!isSetter(getter) && !isGetter(getter)) {
            throw new ConfigurationException("class " + c.getCanonicalName() + " has the method " + m.getName() + " marked as property. only getters or setters can be marked as properties.");

        } else {
            try {
                setter = c.getMethod("set" + m.getName().substring("get".length()), getter.getReturnType());
            } catch (NoSuchMethodException | SecurityException ex) {
                throw new ConfigurationException("class " + c.getCanonicalName() + " has no corresponding setter for: " + m.getName());
            }
        }
    }

    private boolean isGetter(Method m) {
        return m.getName().startsWith("get") && m.getReturnType() != Void.TYPE && m.getParameterTypes().length == 0;
    }

    private boolean isSetter(Method m) {
        return m.getName().startsWith("set") && m.getParameterTypes().length == 1;
    }

    public String getName() {
        return name;
    }

    public boolean isMandatory() {
        return mandatory;
    }

    public String getDefaultValue() {
        return defaultValue;
    }

    public Class getType() {
        return type;
    }

    public boolean isSocket() {
        return sockType != null;
    }

    public Class getKeyType() {
        return keyType;
    }

    public Class getValueType() {
        return valueType;
    }

    public String getDescription() {
        return description;
    }

    public SocketType getSockType() {
        return sockType;
    }

}
